

package top.continew.admin.question.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.continew.admin.common.enums.DisEnableStatusEnum;
import top.continew.admin.question.mapper.question.QuestionSetQuestionMapper;
import top.continew.admin.question.mapper.question.UserDoQuestionMapper;
import top.continew.admin.question.mapper.question.UserDoQuestionSetMapper;
import top.continew.admin.question.model.question.Question;
import top.continew.admin.question.model.question.QuestionSetQuestion;
import top.continew.admin.question.model.question.UserDoQuestion;
import top.continew.admin.question.model.question.UserDoQuestionSet;
import top.continew.admin.question.user.service.IUserQuestionService;
import top.continew.admin.question.user.service.question.enums.ProblemStateEnum;
import top.continew.admin.question.user.service.question.enums.QuestionTypeEnum;
import top.continew.admin.question.user.service.questionset.entity.AbstractQuestionSet;
import top.continew.admin.question.user.service.questionset.entity.WrongQuestionSet;
import top.continew.admin.question.utils.SpringContextHolder;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class UserQuestionService implements IUserQuestionService {
    @Autowired
    private UserDoQuestionSetMapper userDoQuestionSetMapper;

    @Autowired
    private UserDoQuestionMapper userDoQuestionMapper;

    /**
     * 获取启用状态的用户做题集合
     *
     * @param userId        用户ID
     * @param questionSetId 题目集合ID
     * @return 用户做题集合
     */
    @Override
    public UserDoQuestionSet getUserDoQuestionSet(Long userId, String questionSetId) {
        return userDoQuestionSetMapper.selectOne(Wrappers.lambdaQuery(UserDoQuestionSet.class)
            .eq(UserDoQuestionSet::getQuestionSetId, questionSetId)
            .eq(UserDoQuestionSet::getUserId, userId)
            .eq(UserDoQuestionSet::getStatus, DisEnableStatusEnum.ENABLE.getValue())
            .last("limit 1"));
    }

    @Override
    public void saveUserQuestion(List<UserDoQuestion> userDoQuestionList, Long index, AbstractQuestionSet questionSet) {
        if (userDoQuestionList.isEmpty()) {
            return;
        }
        UserDoQuestion last = userDoQuestionList.getLast();
        if (!(questionSet instanceof WrongQuestionSet)) {
            // 检查重复提交
            List<UserDoQuestion> lastDoQuestionList = duplicateSubmission(last.getUserId(), String.valueOf(last
                .getQuestionSetId()), userDoQuestionList);
            if (!lastDoQuestionList.isEmpty()) {
                // 更新简答题
                List<UserDoQuestion> shortAnswer = lastDoQuestionList.stream()
                    .filter(userDoQuestion -> Objects.equals(userDoQuestion
                        .getQuestionType(), (long)QuestionTypeEnum.SHORT_ANSWER_QUESTIONS.getCode()))
                    .toList();
                if (!shortAnswer.isEmpty()) {
                    // 将现有记录转换为Map（以questionId为键，取最后一个元素）
                    Map<Long, UserDoQuestion> existingQuestionsMap = shortAnswer.stream()
                        .collect(Collectors.toMap(UserDoQuestion::getQuestionId, Function.identity(), (u, v) -> v // 同一questionId取最后一个元素
                        ));
                    // 将userDoQuestionList预转换为Map，避免重复遍历
                    Map<Long, UserDoQuestion> newQuestionMap = userDoQuestionList.stream()
                        .collect(Collectors.toMap(UserDoQuestion::getQuestionId, Function.identity(), (u, v) -> v // 同一questionId取最后一个元素
                        ));
                    existingQuestionsMap.forEach((key, oldDoQuestion) -> {
                        UserDoQuestion newDoQuestion = newQuestionMap.get(key);
                        if (newDoQuestion != null) {
                            Long oldId = oldDoQuestion.getId();
                            BeanUtils.copyProperties(newDoQuestion, oldDoQuestion);
                            oldDoQuestion.setId(oldId);
                            userDoQuestionMapper.updateById(oldDoQuestion);
                        }
                    });
                }
                // 过滤不存在于existingQuestionsMap的题目
                userDoQuestionList = userDoQuestionList.stream()
                    .filter(userDoQuestion -> lastDoQuestionList.stream()
                        .noneMatch(doQuestion -> Objects.equals(doQuestion.getQuestionId(), userDoQuestion
                            .getQuestionId())))
                    .toList();
            }
            if (userDoQuestionList.isEmpty()) {
                return;
            }
        } else {
            List<Long> ids = userDoQuestionList.stream()
                .filter(userDoQuestion -> Objects.equals(userDoQuestion.getProblemState(), ProblemStateEnum.RIGHT
                    .getCode()))
                .map(UserDoQuestion::getQuestionId)
                .toList();
            if (!ids.isEmpty()) {
                //更新题目为已掌握
                Objects.requireNonNull(SpringContextHolder.getBean(QuestionSetQuestionMapper.class))
                    .update(null, new LambdaUpdateWrapper<QuestionSetQuestion>(QuestionSetQuestion.class)
                        .set(QuestionSetQuestion::getStatus, 1L)
                        .in(QuestionSetQuestion::getQuestionId, ids)
                        .eq(QuestionSetQuestion::getQuestionSetId, questionSet.getQuestionSet().getId()));
            }
        }
        // 统计本次题目的汇总
        QuestionSummary summary = summarizeQuestions(userDoQuestionList, index);
        // 更新集合
        UserDoQuestionSet userDoQuestionSet = changeUserQuestionSet(last, summary);
        // 批量插入记录
        batchInsertQuestions(userDoQuestionList, userDoQuestionSet.getId());
    }

    /**
     * 批量插入用户做题记录
     *
     * @param userDoQuestionList 用户做题列表
     * @param questionSetId      题目集合ID
     */
    private void batchInsertQuestions(List<UserDoQuestion> userDoQuestionList, Long questionSetId) {
        Date now = new Date();
        userDoQuestionList.forEach(question -> {
            question.setUserDoQuestionSetId(questionSetId);
            question.setCreateTime(now);
            question.setOperateTime(now);
        });
        userDoQuestionMapper.insertBatch(userDoQuestionList);
    }

    /**
     * 获取重复提交
     *
     * @param userId             用户ID
     * @param questionSetId      题目集合ID
     * @param userDoQuestionList 用户做题列表
     */
    private List<UserDoQuestion> duplicateSubmission(Long userId,
                                                     String questionSetId,
                                                     List<UserDoQuestion> userDoQuestionList) {
        UserDoQuestionSet userDoQuestionSet = getUserDoQuestionSet(userId, questionSetId);
        if (userDoQuestionSet != null) {
            List<Long> questionIds = userDoQuestionList.stream().map(UserDoQuestion::getQuestionId).toList();
            return userDoQuestionMapper.selectList(Wrappers.lambdaQuery(UserDoQuestion.class)
                .eq(UserDoQuestion::getUserDoQuestionSetId, userDoQuestionSet.getId())
                .in(UserDoQuestion::getQuestionId, questionIds));
        }
        return List.of();
    }

    private QuestionSummary summarizeQuestions(List<UserDoQuestion> userDoQuestionList, Long index) {
        Map<Integer, Long> stateCounts = userDoQuestionList.stream()
            .collect(Collectors.groupingBy(UserDoQuestion::getProblemState, Collectors.counting()));
        long doSum = userDoQuestionList.size();
        long trueSum = stateCounts.getOrDefault(ProblemStateEnum.RIGHT.getCode(), 0L);
        long falseSum = stateCounts.getOrDefault(ProblemStateEnum.WRONG.getCode(), 0L);
        long doTime = userDoQuestionList.stream().mapToLong(UserDoQuestion::getDoTime).sum();
        return new QuestionSummary(doSum, trueSum, falseSum, doTime, index);
    }

    private UserDoQuestionSet changeUserQuestionSet(UserDoQuestion userDoQuestion, QuestionSummary summary) {
        // 获取启用的用户做题集合
        UserDoQuestionSet userDoQuestionSet = getUserDoQuestionSet(userDoQuestion.getUserId(), String
            .valueOf(userDoQuestion.getQuestionSetId()));

        // 初始化或获取现有记录
        if (userDoQuestionSet == null) {
            userDoQuestionSet = initializeQuestionSet(userDoQuestion, summary);
            userDoQuestionSetMapper.insert(userDoQuestionSet);
        } else {
            updateQuestionSet(userDoQuestionSet, userDoQuestion, summary);
            userDoQuestionSetMapper.updateById(userDoQuestionSet);
        }
        return userDoQuestionSet;
    }

    /**
     * 初始化新的做题集合
     */
    private UserDoQuestionSet initializeQuestionSet(UserDoQuestion userDoQuestion, QuestionSummary summary) {
        UserDoQuestionSet userDoQuestionSet = new UserDoQuestionSet();
        userDoQuestionSet.setQuestionSetId(userDoQuestion.getQuestionSetId());
        userDoQuestionSet.setUserId(userDoQuestion.getUserId());
        userDoQuestionSet.setBeginTime(new Date(System.currentTimeMillis() - summary.getDoTime() * 1000));
        userDoQuestionSet.setDoSum(summary.getDoSum());
        userDoQuestionSet.setCurrentIndex(summary.getIndex());
        userDoQuestionSet.setDoTime(summary.getDoTime());
        userDoQuestionSet.setEndTime(new Date());
        userDoQuestionSet.setStatus(DisEnableStatusEnum.ENABLE.getValue());

        updateProblemStateCount(userDoQuestionSet, userDoQuestion, summary, false);
        return userDoQuestionSet;
    }

    /**
     * 更新现有做题集合
     */
    private void updateQuestionSet(UserDoQuestionSet userDoQuestionSet,
                                   UserDoQuestion userDoQuestion,
                                   QuestionSummary summary) {
        userDoQuestionSet.setCurrentIndex(summary.getIndex());
        Long currentDoSum = userDoQuestionSet.getDoSum();
        userDoQuestionSet.setDoSum(currentDoSum != null ? currentDoSum + summary.getDoSum() : summary.getDoSum());
        Long currentDoTime = userDoQuestionSet.getDoTime();
        userDoQuestionSet.setDoTime(currentDoTime != null ? currentDoTime + summary.getDoTime() : summary.getDoTime());
        userDoQuestionSet.setEndTime(new Date());

        updateProblemStateCount(userDoQuestionSet, userDoQuestion, summary, true);
    }

    /**
     * 更新题目状态计数
     */
    private void updateProblemStateCount(UserDoQuestionSet userDoQuestionSet,
                                         UserDoQuestion userDoQuestion,
                                         QuestionSummary summary,
                                         boolean isUpdate) {
        Integer problemState = userDoQuestion.getProblemState();
        if (problemState == null) {
            return;
        }

        boolean isRight = ProblemStateEnum.RIGHT.getCode().equals(problemState);
        boolean isWrong = ProblemStateEnum.WRONG.getCode().equals(problemState);

        if (isRight || isWrong) {
            Long currentSum = isRight ? userDoQuestionSet.getTrueSum() : userDoQuestionSet.getFalseSum();
            Long summaryValue = isRight ? summary.getTrueSum() : summary.getFalseSum();
            Long newValue = isUpdate && currentSum != null ? currentSum + summaryValue : summaryValue;

            if (isRight) {
                userDoQuestionSet.setTrueSum(newValue);
            } else {
                userDoQuestionSet.setFalseSum(newValue);
            }
        }
    }

    @Override
    public List<UserDoQuestion> getListByUserId(Long userId, String questionSetId) {
        UserDoQuestionSet userDoQuestionSet = getUserDoQuestionSet(userId, questionSetId);
        if (userDoQuestionSet == null) {
            return List.of();
        }
        return userDoQuestionMapper.selectList(Wrappers.lambdaQuery(UserDoQuestion.class)
            .eq(UserDoQuestion::getQuestionSetId, questionSetId)
            .eq(UserDoQuestion::getUserId, userId)
            .eq(UserDoQuestion::getUserDoQuestionSetId, userDoQuestionSet.getId()));
    }

    @Override
    public List<UserDoQuestion> getAllListByUserId(Long userId, String questionSetId, Long specificationType) {
        MPJLambdaWrapper<UserDoQuestion> wrapper = new MPJLambdaWrapper<UserDoQuestion>()
            .leftJoin(Question.class, Question::getId, UserDoQuestion::getQuestionId)
            .eq(Question::getOnlineStatus, 1L)
            .ne(Question::getType, QuestionTypeEnum.MATERIAL_QUESTIONS.getCode())
            .eq(UserDoQuestion::getUserId, userId)
            .eq(UserDoQuestion::getQuestionSetId, questionSetId)
            .eq(Question::getSpecificationType, specificationType);
        return userDoQuestionMapper.selectList(wrapper);
    }

    @Override
    public UserDoQuestion getInfo(Long userId, Long questionId, Long questionSetId) {
        UserDoQuestionSet userDoQuestionSet = getUserDoQuestionSet(userId, String.valueOf(questionSetId));
        if (userDoQuestionSet == null) {
            return null;
        }
        return userDoQuestionMapper.selectOne(Wrappers.lambdaQuery(UserDoQuestion.class)
            .eq(UserDoQuestion::getQuestionSetId, questionSetId)
            .eq(UserDoQuestion::getUserId, userId)
            .eq(UserDoQuestion::getQuestionId, questionId)
            .eq(UserDoQuestion::getUserDoQuestionSetId, userDoQuestionSet.getId())
            .orderByDesc(UserDoQuestion::getCreateTime)
            .last("limit 1"));
    }

    @Override
    public void clearQuestionSetRecord(long questionSetId, Long userId) {
        UserDoQuestionSet userDoQuestionSet = getUserDoQuestionSet(userId, String.valueOf(questionSetId));
        if (userDoQuestionSet != null) {
            userDoQuestionSet.setStatus(DisEnableStatusEnum.DISABLE.getValue());
            userDoQuestionSetMapper.updateById(userDoQuestionSet);
        }
    }

    @Override
    public Long getUserIndex(Long userId, long questionSetId) {
        UserDoQuestionSet userDoQuestionSet = getUserDoQuestionSet(userId, String.valueOf(questionSetId));
        if (userDoQuestionSet != null) {
            return userDoQuestionSet.getCurrentIndex();
        }
        return 1L;
    }

    @Override
    public UserDoQuestion getDoQuestionInfo(long questionSetId, Long userId, Long questionId) {
        UserDoQuestionSet userDoQuestionSet = getUserDoQuestionSet(userId, String.valueOf(questionSetId));
        if (userDoQuestionSet != null) {
            return userDoQuestionMapper.selectOne(Wrappers.lambdaQuery(UserDoQuestion.class)
                .eq(UserDoQuestion::getQuestionSetId, questionSetId)
                .eq(UserDoQuestion::getUserId, userId)
                .eq(UserDoQuestion::getQuestionId, questionId)
                .eq(UserDoQuestion::getUserDoQuestionSetId, userDoQuestionSet.getId())
                .orderByDesc(UserDoQuestion::getCreateTime)
                .last("limit 1"));
        }
        return null;
    }

    @Override
    public Long getDoQuestionSumBySpecificationType(Long userId, Long specificationType) {
        MPJLambdaWrapper<UserDoQuestion> wrapper = new MPJLambdaWrapper<UserDoQuestion>().select("t.question_id")
            .leftJoin(Question.class, Question::getId, UserDoQuestion::getQuestionId)
            .ne(Question::getType, QuestionTypeEnum.MATERIAL_QUESTIONS.getCode())
            .eq(UserDoQuestion::getUserId, userId)
            .eq(Question::getSpecificationType, specificationType);
        return userDoQuestionMapper.selectCount(wrapper);
    }

    @Override
    public long getDoQuestionSum(Long userId, Long questionSetId) {
        return this.getDoQuestionSum(userId, questionSetId, null);
    }

    @Override
    public long getDoQuestionSum(Long userId, Long questionSetId, ProblemStateEnum problemStateEnum) {
        UserDoQuestionSet userDoQuestionSet = getUserDoQuestionSet(userId, String.valueOf(questionSetId));
        if (userDoQuestionSet == null) {
            return 0L;
        }
        if (problemStateEnum != null) {
            MPJLambdaWrapper<UserDoQuestion> wrapper = new MPJLambdaWrapper<UserDoQuestion>().select("t.question_id")
                .leftJoin(Question.class, Question::getId, UserDoQuestion::getQuestionId)
                .ne(Question::getType, QuestionTypeEnum.MATERIAL_QUESTIONS.getCode())
                .eq(UserDoQuestion::getUserId, userId)
                .eq(Question::getOnlineStatus, 1L)
                .eq(UserDoQuestion::getUserDoQuestionSetId, userDoQuestionSet.getId())
                .eq(UserDoQuestion::getQuestionSetId, questionSetId)
                .eq(UserDoQuestion::getProblemState, problemStateEnum.getCode());
            return userDoQuestionMapper.selectCount(wrapper);
        }
        MPJLambdaWrapper<UserDoQuestion> wrapper = new MPJLambdaWrapper<UserDoQuestion>().select("t.question_id")
            .leftJoin(Question.class, Question::getId, UserDoQuestion::getQuestionId)
            .ne(Question::getType, QuestionTypeEnum.MATERIAL_QUESTIONS.getCode())
            .eq(UserDoQuestion::getUserId, userId)
            .eq(Question::getOnlineStatus, 1L)
            .eq(UserDoQuestion::getUserDoQuestionSetId, userDoQuestionSet.getId())
            .eq(UserDoQuestion::getQuestionSetId, questionSetId);
        return userDoQuestionMapper.selectCount(wrapper);
    }

    @Override
    public Long getDoQuestionDay(Long userId, Long specificationType) {
        //日期分组统计
        return userDoQuestionMapper.getDoQuestionDay(userId, specificationType);
    }

    @Override
    public Long getQuestionLastTimeDoSum(Long userId, Long specificationType) {
        return userDoQuestionMapper.getQuestionLastTimeDoSum(userId, specificationType);
    }

    @Override
    public Long getQuestionTodayDoSum(Long userId, Long specificationType) {
        return userDoQuestionMapper.getQuestionTodayDoSum(userId, specificationType);
    }
}
